/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       application.cpp
 * Author:     karooolek
 * Created on: 2009-01-06
 *
 **********************************************************************************************************************/

#include "application.h"

namespace mGameEngine
{
namespace System
{

Application *Application::_app = NULL;

void Application::_glutDisplayFunc(void)
{
    // draw application
    _app->draw();
    glutSwapBuffers();

    // update frames counter
    ++(Window::_frames);
}

void Application::_glutIdleFunc(void)
{
    _app->idle();

    glutPostRedisplay();
}

Application::Application() :
    _name("mGameEngine::Application"), _version("0.0")
{
    static int argc = 1;
    static char *args[] = {"mGameEngine"};

    // initialize libs
    glutInit(&argc, args);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutCreateWindow(_name);

    alutInit(&argc, args);

    NxPhysicsSDK *physx = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
    NxCookingInterface *cooking = NxGetCookingLib(NX_PHYSICS_SDK_VERSION);
    cooking->NxInitCooking();

#ifdef WIN32
    WSAData wsaData;
    WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif
}

Application::Application(const String &name, const String &version) :
    _name(name), _version(version)
{
    static int argc = 1;
    static char *args[] = {"mGameEngine"};

    // initialize libs
    glutInit(&argc, args);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutCreateWindow(_name);

    alutInit(&argc, args);

    NxPhysicsSDK *physx = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);

#ifdef _DEBUG
    physx->getFoundationSDK().getRemoteDebugger()->connect("localhost", 5425);
#endif

    NxCookingInterface *cooking = NxGetCookingLib(NX_PHYSICS_SDK_VERSION);
    cooking->NxInitCooking();

#ifdef WIN32
    WSAData wsaData;
    WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif
}

Application::~Application()
{
    _app = NULL;

    NxPhysicsSDK *physx = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
    physx->release();
    
    NxCookingInterface *cooking = NxGetCookingLib(NX_PHYSICS_SDK_VERSION);
    cooking->NxCloseCooking();

#ifdef WIN32
    WSACleanup();
#endif
}

void Application::_run()
{
    // one application already running
    if(_app)
    {
        return;
    }

    // set application as current
    _app = this;

//    static int argc = 1;
//    static char *args[] = {"mGameEngine"};

    // initialize OpenGL
//    glutInit(&argc, args);
//    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
//    glutCreateWindow(_name);

//    // enter full screen
//    glutGameModeString("1920x1080");
//    if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE))
//    {
//        glutEnterGameMode();
//    }
//    else
//    {
//        printf("The select mode is not available\n");
//        exit(1);
//    }
    glutReshapeFunc(Window::_glutReshapeFunc);

    glutKeyboardFunc(Input::Keyboard::_glutKeyboardFunc);
    glutKeyboardUpFunc(Input::Keyboard::_glutKeyboardUpFunc);
    glutSpecialFunc(Input::Keyboard::_glutKeyboardSpecialFunc);
    glutSpecialUpFunc(Input::Keyboard::_glutKeyboardSpecialUpFunc);

    glutMouseFunc(Input::Mouse::_glutMouseFunc);
    glutMotionFunc(Input::Mouse::_glutMouseMotionFunc);
    glutPassiveMotionFunc(Input::Mouse::_glutMouseMotionFunc);

    glutIdleFunc(_glutIdleFunc);
    glutDisplayFunc(_glutDisplayFunc);

    // initialize OpenAL
//    alutInit(&argc, args);

    // initialize PhysX
//    NxPhysicsSDK *physx = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
//    NxCookingInterface *cooking = NxGetCookingLib(NX_PHYSICS_SDK_VERSION);
//    cooking->NxInitCooking();

#ifdef WIN32
    // initialize winsock
//    WSAData wsaData;
//    WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif

    // TODO what if some initialization fails???

    // begin application
    _app->begin();

    // enter main loop
    glutMainLoop();

    // end application
    _app->end();

    // close OpenGL

    // close OpenAL

    // close PhysX
//    physx->release();
//    cooking->NxCloseCooking();

#ifdef WIN32
    // close winsock
//    WSACleanup();
#endif
}

void Application::begin()
{
}

void Application::end()
{
}

void Application::idle()
{
    if(_stop)
    {
        delete this;
        exit(0);
    }
}

void Application::draw() const
{
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glRasterPos2f(-0.95f, -0.95f);
    glColor4fv(Color(1.0f, 1.0f, 1.0f, 1.0f));

    const String str = "Welcome to mGameEngine! FPS = " +
                        String(Window::getFramesPerSecond());
    for(const char *p = str.c_str(); *p; ++p)
    {
        glutBitmapCharacter(GLUT_BITMAP_8_BY_13, *p);
    }
}

}
}
